package com.javadaemon.rpgengine.util;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.List;

import org.newdawn.slick.Color;
import org.newdawn.slick.Image;
import org.newdawn.slick.SlickException;

import com.javadaemon.rpgengine.model.TILE_OBJECT;
import com.javadaemon.rpgengine.model.TILE_TYPE;
import com.javadaemon.rpgengine.model.Tile;
import com.javadaemon.rpgengine.model.TileMap;
import com.javadaemon.rpgengine.model.TileObject;
import com.javadaemon.rpgengine.util.ResourceManager.MAP;


/*
 Copyright (c) 2011, Morten Andersen
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 notice, this list of conditions and the following disclaimer in the
 documentation and/or other materials provided with the distribution.
 * The name of the author may not be used to endorse or promote products
 derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL MORTEN ANDERSEN BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * This class contains logic for instantiating a TileMap.
 * 
 * @author Somnium, JavaDaemon
 * 
 */
public class MapLoader {
    
    public static TileMap createMap(MAP map) throws SlickException {
	// Initialize the terrain
	String imageFilename = map.getImageFile();
	TileMap tilemap = loadObjects(createMapFromImage(imageFilename), map.getObjectsFile());
	return tilemap;
    }

    /**
     * This method instantiates a TileMap instance by using an image file, by deriving the tile types from the pixel colors in that image.
     * 
     * @param imageName
     *            The filename of the image
     * @return
     * @throws SlickException
     */
    public static TileMap createMapFromImage(String filename)
	    throws SlickException {
	TileMap returnValue = null;

	// Get the image - The resource manager is not used for this image, since it is only used this once,
	// and is then cleared from PC memory (i.e. we don't want to cache it).
	Image img = new Image(filename);
	int width = img.getWidth();
	int height = img.getHeight();
	returnValue = new TileMap(width, height);

	// Loop through the pixel, transforming each pixel into a Tile of the corresponding type.
	for (int x = 0; x < width; x++) {
	    for (int y = 0; y < height; y++) {
		Color color = img.getColor(x, y);
		TILE_TYPE type = getTiletypeFromColor(color.getRedByte(),
			color.getGreenByte(), color.getBlueByte());
		if (type != null) {
		    Tile tile = new Tile(type);
		    returnValue.setTile(x, y, tile);
		}
	    }
	}
	img.destroy(); // Clear the image from memory
	img = null;

	return returnValue;
    }

    /**
     * Helper method, for mapping a color into a tile type.
     * 
     * @param r
     *            The red part of the color
     * @param g
     *            The green part of the color
     * @param b
     *            The blue part of the color
     * @return The mapped tile type, or null if the color did not map to any type.
     */
    private static TILE_TYPE getTiletypeFromColor(int r, int g, int b) {
	if (r == 0 && g == 255 && b == 0) // Pure green
	{
	    return TILE_TYPE.GRASS;
	} else if (r == 0 && g == 200 && b == 0) // Millitary green
	{
	    return TILE_TYPE.SMALL_TREE;
	} else if (r == 0 && g == 50 && b == 0)
	{
	    return TILE_TYPE.BIG_TOP;
	} else if (r == 0 && g == 10 && b == 0)
	{
	    return TILE_TYPE.BIG_STUMP;
	} else if (r == 255 && g == 255 && b == 255) // Pure white
	{
	    return TILE_TYPE.GROUND;
	} else {
	    return null;
	}
    }
    
    @SuppressWarnings("unchecked")
    private static TileMap loadObjects(TileMap map, String objectsPath) {
	try {
	    List<WorldObject> list = (List<WorldObject>)XStreamUtil.getXStream().fromXML(new FileInputStream(objectsPath));
	    for (WorldObject e : list) {
		    Tile tile = map.getTile(e.getX(), e.getY());
		    TileObject object = new TileObject(e.getType());
		    tile.setObject(object);
		}
	} catch (FileNotFoundException e1) {
	    e1.printStackTrace();
	}
	return map;
    }
    
    /**
     * This class represents a world object after it has been loaded, and it yet to be
     * added to the actual TileMap. It is only used during loading.
     * @author Mads Horndrup
     *
     */
    public class WorldObject {
	
	private int X, Y;
	private TILE_OBJECT type;
	
	public int getX() {
	    return X;
	}
	
	public int getY() {
	    return Y;
	}
	
	public TILE_OBJECT getType() {
	    return type;
	}
    }

}
